package model;

import java.util.ArrayList;
import java.util.List;

import model.auxillary.Parameter;
import model.auxillary.ParameterList.ParameterType;
import model.auxillary.Tool;

/**
 * A {@code PartProcess} is a part process of a {@code ManufacturingMethod}.
 * It allows modeling parts of a whole process. It also allows modeling
 * different geometry sets like i.e. the shoulders of an axle.
 * @author Oliver Eckstein & Sebastian Perlwitz
 *
 */
public abstract class PartProcess extends Process {
	
	/**
	 * The linked manufacturing method of this part process.
	 */
	protected ManufacturingMethod manuMethod;
	
	/**
	 * The tool belonging to this part process.
	 */
	protected Tool tool;
	
	/**
	 * The rank of this {@code PartProcess} inside it's 
	 * {@code ManufacturingMethod}. It is used to give parameters a unique
	 * abbreviation.
	 */
	protected int rank;
	
	/**
	 * The textPartProcDescription of this {@code PartProcess} resembles the
	 * text that is used to describe the name of a geometry set. For example
	 * the text field "Zonenbeschreibung" in {@code PartProcessReflowSoldering}
	 */
	protected String textPartProcDescription;
	
	/**
	 * To create a new instance of a {@code PartProcess}.
	 * @param manuMethod the {@code ManufacturingMethod} that holds the part
	 * process.
	 * @param id a unique ID that identifies this part process.
	 * @param the rank of this {@code PartProcess} inside it's
	 * {@code ManufacturingMethod}.
	 * @param textPartProcDescription the name of the part process description
	 * text field. For example the text field "Zonenbeschreibung" in
	 * {@code PartProcessReflowSoldering}.
	 */
	public PartProcess(
			ManufacturingMethod manuMethod,
			String id,
			int rank,
			String textPartProcDescription) {
		super(manuMethod.getPartProCount() + ". Teilprozess", id);		
		this.manuMethod = manuMethod;
		this.textPartProcDescription = textPartProcDescription;
		this.rank = rank;
		
		// To register every observer of the manufacturing method to this
		// part process.
		this.getObservers().addAll(manuMethod.getObservers());
	}
	
	/**
	 * To compute and set the physical minimum effectiveness of this
     * {@code PartProcess}.     
	 * @param eActPP the measured energy consumption <b>E<sub>ist</sub></b> [Wh].
	 * @param eMinPhyPP the computed physical minimum energy consumption
	 * <b>E<sub>min,tech,i</sub></b> [Wh].
	 * @return the physical minimum effectiveness <b>&eta;<sub>phy,i</sub></b>
	 * [1].
	 */
	public double setPhysEffectivenessPartProcess(double eActPP, double eMinPhyPP) {    	
        double eta = eMinPhyPP / eActPP * 100; //Old EEV!
        
        if (Double.isInfinite(eta) || Double.isNaN(eta)) {
            error = true;
        }        
        getParameter(
        		"eta_phy", ParameterType.RESULT_PARAMETER).setValue(eta);
        return eta;
    }	
	
	/**
	 * To compute and set the technological minimum effectiveness of this
     * {@code PartProcess}.     
	 * @param eActPP the measured energy consumption <b>E<sub>ist</sub></b> [Wh].
	 * @param eMinTechPP the computed technological minimum energy consumption
	 * <b>E<sub>min,tech,i</sub></b> [Wh].
	 * @return the technological minimum effectiveness
	 * <b>&eta;<sub>tech,i</sub></b> [1].
	 */
	public double setTechnEffectivenessPartProcess(double eActPP, double eMinTechPP) {    	
        double eta = eMinTechPP / eActPP * 100; //Old EEV!
        
        if (Double.isInfinite(eta) || Double.isNaN(eta)) {
            error = true;
        }        
        getParameter(
        		"eta_tech", ParameterType.RESULT_PARAMETER).setValue(eta);
        return eta;
    }	
	
	/**
	 * To compute and set the real minimum effectiveness of this
     * {@code PartProcess}.     
	 * @param eActPP the measured energy consumption <b>E<sub>ist</sub></b> [Wh].
	 * @param eMinRealPP the computed real minimum energy consumption
	 * <b>E<sub>min,real,i</sub></b> [Wh].
	 * @return the real minimum effectiveness <b>&eta;<sub>real,i</sub></b> [1].
	 */
	public double setRealEffectivenessPartProcess(double eActPP, double eMinRealPP) {    	
        double eta = eMinRealPP / eActPP * 100; //Old EEV!
        
        if (Double.isInfinite(eta) || Double.isNaN(eta)) {
            error = true;
        }        
        getParameter(
        		"eta_real", ParameterType.RESULT_PARAMETER).setValue(eta);
        return eta;
    }	
	
	/**
	 * To set the physical minimum energy consumption of this
	 * {@code PartProcess}.
	 * @param eMinPhyPP the physical minimum energy of this {@code PartProcess}.
	 */
	public void setPhysMinEnergyPartProcess(double eMinPhyPP)
	{    	
    	getParameter("E_min,phy",
    			ParameterType.RESULT_PARAMETER).setValue(eMinPhyPP);
	}
	
	/**
	 * To set the technological minimum energy consumption of this
	 * {@code PartProcess}.
	 * @param eMinTechPP the technological minimum energy of this
	 * {@code PartProcess}.
	 */
	public void setTechMinEnergyPartProcess(double eMinTechPP)
	{    	
    	getParameter(
    			"E_min,tech",
    			ParameterType.RESULT_PARAMETER).setValue(eMinTechPP);
	}
	
	/**
	 * To set the technological minimum energy consumption of this
	 * {@code PartProcess}.
	 * @param eMinRealPP the real minimum energy of this {@code PartProcess}.
	 */
	public void setRealMinEnergyPartProcess(double eMinRealPP)
	{    	
    	getParameter("E_min,real",
    			ParameterType.RESULT_PARAMETER).setValue(eMinRealPP);
	}
	
	/**
	 * To link a tool to this {@code PartProcess}.
	 * @param tool the tool to be linked.
	 */
	public void setTool(Tool tool) {		
		this.tool = tool;		
	}
	
	/**
	 * To find out whether this {@code PartProcess} is linked to a tool.
	 * @return {@code true} when set is linked to a tool, {@code false}
	 * otherwise. 
	 */
	public boolean hasTool() {
		return (tool == null) ? false : true;
	}
	
	/**
	 * To get the tool of this {@code PartProcess}.
	 * @return the tool.
	 */
	public Tool getTool() {
		return tool;
	}
	
	/**
	 * To get the the name of the process description text field.
	 * @return the name of the process description text field.
	 */
	public String getTextPartProcDescription(){
		return textPartProcDescription;
	}

	@Override
	protected void addParameters() {
		List<Parameter> newParams = new ArrayList<Parameter>();
		newParams.add(new Parameter(
                "Gemessener Energieverbrauch Teilprozess",
                "E_ist," + rank,
                "<html>E<sub>ist," + rank + "</sub></html>",
                "[Wh]",
				true,
				this));
		parameters.addParameters(ParameterType.GEOMETRY_PARAMETER, newParams);

		newParams.clear();
		
		newParams.add(new Parameter(
                "Physikalisches Energieminimum Teilprozess",
                "E_min,phy," + rank,
                "<html>E<sub>min,phy," + rank + "</sub></html>",
                "[Wh]",
				false,
				this));	
		
		newParams.add(new Parameter(
                "Technologisches Energieminimum Teilprozess",
                "E_min,tech," + rank,
                "<html>E<sub>min,tech," + rank + "</sub></html>",
                "[Wh]",
				false,
				this));	
		
		newParams.add(new Parameter(
                "Reales Energieminimum Teilprozess",
                "E_min,real," + rank,
                "<html>E<sub>min,real," + rank + "</sub></html>",
                "[Wh]",
				false,
				this));		
		
		newParams.add(new Parameter(
                "Physikalische relative Energieeffizienz Teilprozess",
                "eta_phy," + rank,
                "<html>REE<sub>phy," + rank + "</sub></html>",
                "[%]",
				false,
				this));
		
		newParams.add(new Parameter(
                "Technologische relative Energieeffizienz Teilprozess",
                "eta_tech," + rank,
                "<html>REE<sub>tech," + rank + "</sub></html>",
                "[%]",
				false,
				this));
		
		newParams.add(new Parameter(
                "Reale relative Energieeffizienz Teilprozess",
                "eta_real," + rank,
                "<html>REE<sub>real," + rank + "</sub></html>",
                "[%]",
				false,
				this));
		parameters.addParameters(ParameterType.RESULT_PARAMETER, newParams);
	}
	
	@Override
	public Parameter getParameter(String abbreviation, ParameterType type) {

		if(type != ParameterType.TOOL_PARAMETER) {
			// An example: To find the parameter 'f_lambda,1' by searching for
			// 'f_lambda'.
			String a = abbreviation + "_" + rank;
			String b = abbreviation + "," + rank;
			Parameter paramA = parameters.getParameter(type, a);
			Parameter paramB = parameters.getParameter(type, b);
			if(paramA == null) {
				return paramB;
			} else {
				return paramA;
			}				
		} else {
			// A tool parameter is what we are looking for.
			return tool.getParameterByAbbrev(abbreviation);
		}				
	}
	
	@Override
    public void update() {
    	calculated = false;   
    	manuMethod.update();
    	notifyObservers();    	
    }
}
